import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common'
import { JwtService } from '@nestjs/jwt'
import { Request } from 'express'
import { RedisService } from '@/src/redis/redis.service'

@Injectable()
export class JwtAuthGuard implements CanActivate {
  constructor(
    private readonly jwtService: JwtService,
    private readonly redisService: RedisService
  ) { }

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest<Request>()
    const token = this.extractTokenFromHeader(request)

    if (!token) {
      throw new UnauthorizedException('请先登录')
    }

    try {
      // 验证JWT签名是否有效
      const payload = this.jwtService.verify(token)

      const userId = payload.id
      if (!userId) {
        throw new UnauthorizedException('token格式无效')
      }

      // 从Redis中查询该用户的有效token
      const storedToken = await this.redisService.get(`token_${userId}`)

      // 校验Redis中的token是否与当前请求的token一致
      if (!storedToken || storedToken !== token) {
        throw new UnauthorizedException('token已过期或已被注销')
      }

      // 验证通过，将用户信息附加到请求对象
      request.user = payload
      return true
    } catch (error) {
      // 统一捕获所有验证失败的情况（签名无效、Redis未匹配等）
      throw new UnauthorizedException('无效的token或已过期')
    }
  }

  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? []
    return type === 'Bearer' ? token : (token || request.headers.authorization)
  }
}